package sf.dsl.example;

/**
 * {@code WindowRows} provides the building of the rows/range part of the window function expression
 * @param <A> expression type
 * @author tiwe
 */
public class WindowRows {

    private static final String AND = " and";

    private static final String BETWEEN = " between";

    private static final String CURRENT_ROW = " current row";

    private static final String FOLLOWING = " following";

    private static final String PRECEDING = " preceding";

    private static final String UNBOUNDED = " unbounded";

    /**
     * Intermediate step
     */
    public class Between {

        public BetweenAnd unboundedPreceding() {
            str.append(UNBOUNDED);
            str.append(PRECEDING);
            return new BetweenAnd();
        }

        public BetweenAnd currentRow() {
            str.append(CURRENT_ROW);
            return new BetweenAnd();
        }

        public BetweenAnd preceding(int i) {
            str.append(PRECEDING);
            str.append(" ").append(i);
            return new BetweenAnd();
        }

        public BetweenAnd following(int i) {
            str.append(FOLLOWING);
            str.append(" ").append(i);
            return new BetweenAnd();
        }
    }

    /**
     * Intermediate step
     */
    public class BetweenAnd {

        public BetweenAnd() {
            str.append(AND);
        }

        public WindowFunction unboundedFollowing() {
            str.append(UNBOUNDED);
            str.append(FOLLOWING);
            return rv.withRowsOrRange(str.toString());
        }

        public WindowFunction currentRow() {
            str.append(CURRENT_ROW);
            return rv.withRowsOrRange(str.toString());
        }

        public WindowFunction preceding(int expr) {
            str.append(PRECEDING);
            str.append(" ").append(expr);
            return rv.withRowsOrRange(str.toString());
        }

        public WindowFunction following(int i) {
            str.append(FOLLOWING);
            str.append(" ").append(i);
            return rv.withRowsOrRange(str.toString());
        }
    }

    private final WindowFunction rv;

    private final StringBuilder str = new StringBuilder();

    public WindowRows(WindowFunction windowFunction, String prefix) {
        this.rv = windowFunction;
        str.append(prefix);
    }

    public Between between() {
        str.append(BETWEEN);
        return new Between();
    }

    public WindowFunction unboundedPreceding() {
        str.append(UNBOUNDED);
        str.append(PRECEDING);
        return rv.withRowsOrRange(str.toString());
    }

    public WindowFunction currentRow() {
        str.append(CURRENT_ROW);
        return rv.withRowsOrRange(str.toString());
    }

    public WindowFunction preceding(int i) {
        str.append(PRECEDING);
        str.append(" ").append(i);
        return rv.withRowsOrRange(str.toString());
    }
}
